/**
 * author: TYF
 * created on: 2019/2/25 12:11
 * description:
 */
package com.tx.txlibs;

import android.content.Context;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbManager;
import android.util.Log;

import java.util.Arrays;
import java.util.HashMap;


public class MUR500Cls {
    private static final String TAG = "Tx_MUR500Cls";
    private static Context context = null;
    private static UsbManager mUsbManager;
    private static UsbDevice mUsbDevice;
    private static UsbEndpoint endpoint_in = null;
    private static UsbEndpoint endpoint_out = null;
    private static UsbInterface mInterface;
    private static UsbDeviceConnection mDeviceConnection = null; //通讯使用该Connection
    private static final int VendorID = 0x5458;   //芯片/模块的VID; 要和device_filter.xml中的定义一样！
    private static final int ProductID = 0x0002;  //芯片/模块的PID; 要和device_filter.xml中的定义一样！
    //上面这些变量不要改动

    private MUR500Cls(){}

    public static void setContext(Context context) {
        MUR500Cls.context = context;
    }


    // 打开发卡器
    public static int murOpen() {
        if (context == null) {
            Log.d(TAG, "murOpen: please set context first");
            return 0;
        }

        if (mDeviceConnection != null) {
            Log.d(TAG, "murOpen: 设备已经打开,请不要重复打开");
            return 1;
        }

        mUsbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
        if (mUsbManager == null) {
            Log.d(TAG, "murOpen: mUsbManager == null");
            return -1;
        }
        HashMap<String, UsbDevice> deviceList = mUsbManager.getDeviceList();
        if (deviceList.isEmpty()) { //空
            Log.d(TAG, "murOpen: deviceList == null");
            return -2;
        }
        mUsbDevice = null;
        for (UsbDevice device : deviceList.values()) {
            if ((device.getVendorId() == VendorID) && (device.getProductId() == ProductID)) {
                mUsbDevice = device;
                Log.d(TAG, "murOpen: 枚举成功");
                break;
            }
        }
        if (mUsbDevice == null) {
            Log.d(TAG, "murOpen: 枚举失败");
            return -3;
        }
        //找设备接口
        mInterface = null;
        Log.d("UsbHidComm", "interfaceCounts : " + mUsbDevice.getInterfaceCount());
        for (int i = 0; i < mUsbDevice.getInterfaceCount(); i++) {
            UsbInterface intf = mUsbDevice.getInterface(i);
            if (intf.getInterfaceClass() == 3  //HID Class
                    && intf.getInterfaceSubclass() == 0 //必须0
                    && intf.getInterfaceProtocol() == 0) {
                mInterface = intf;
                Log.d(TAG, "murOpen: 找到指定的设备接口");
                break;
            }
        }
        if (mInterface == null) {
            Log.d(TAG, "murOpen: 没有找到指定的设备接口");
            return -10;
        }
        //打开设备
        UsbDeviceConnection conn = null;
        // 在open前判断是否有连接权限
        if (mUsbManager.hasPermission(mUsbDevice)) {
            conn = mUsbManager.openDevice(mUsbDevice); //打开设备，获取 UsbDeviceConnection对象，连接设备
        } else {
            Log.d(TAG, "murOpen: 没有权限打开设备");
            return -20;
        }
        if (conn == null) {
            Log.d(TAG, "murOpen: 打开设备失败");
            return -21;
        }
        if (conn.claimInterface(mInterface, true)) {
            mDeviceConnection = conn; // 已经连上HID设备
        } else {
            conn.close();
            return -22;
        }

        endpoint_in = mInterface.getEndpoint(0);
        endpoint_out = mInterface.getEndpoint(1);
        if (endpoint_in == null || endpoint_out == null) {
            Log.d(TAG, "murOpen: Endpoint get failed");
            return -23;
        }

        TxUtils.showText(context, "打开设备成功");
        Log.d(TAG, "murOpen: ---------------打开设备成功--------------");
        return 1;
    }

    // 关闭发卡器
    public static int murClose() {
        int TryCnt = 3;
        if (mDeviceConnection != null) {
            while (TryCnt > 0) {//尝试2次
                if (mDeviceConnection.releaseInterface(mInterface)) {
                    mDeviceConnection.close();
                    mDeviceConnection = null;
                    mInterface = null;
                    mUsbDevice = null;
                    mUsbManager = null;
                    Log.d(TAG, "murClose: ---------------关闭设备成功--------------");
                    TxUtils.showText(context, "关闭设备成功");
                    return 1;
                } else {
                    Log.d(TAG, "murClose: try again " + TryCnt);
                    TryCnt--;
                }
            }

            // 这里强制关闭, 释放
            mDeviceConnection.close();
            mDeviceConnection = null;
            mInterface = null;
            mUsbDevice = null;
            mUsbManager = null;
            Log.d(TAG, "murClose: release interface failed, 已强制关闭设备");
            return -1;
        } else {
            Log.d(TAG, "murClose: no dev connected");
        }
        return 0;
    }


    // HID读卡器数据传输, 会自动打开设备
    public static int callbakHidTransceive(byte[] psendbuff, byte[] precbuff) {
        int len;
        byte buf[] = new byte[64];

        if (mDeviceConnection == null) {
            Log.d(TAG, "callbakHidTransceive: 设备未打开, 尝试打开设备");
            if (murOpen() <= 0) {
                return 0;
            }
        }

        do {
            len = mDeviceConnection.bulkTransfer(endpoint_in, buf, 64, 1); // 尝试读, 清空接收缓冲区
        } while (len > 0);

        len = mDeviceConnection.bulkTransfer(endpoint_out, psendbuff, 64, 1000); // 发送命令
        Log.d(TAG, "callbakHidTransceive: sen_data=>" + TxUtils.bytesToHexString(psendbuff));
        if (len != 64) {
            Log.d(TAG, "callbakHidTransceive: 发送失败, len=" + len);
            murClose();
            return 0;
        }

        Arrays.fill(buf, (byte) 0);
        Arrays.fill(precbuff, (byte) 0);
        len = mDeviceConnection.bulkTransfer(endpoint_in, buf, 64, 1000); // 接收应答
        if (len > 0) {
            System.arraycopy(buf, 0, precbuff, 0, 64);
            Log.d(TAG, "callbakHidTransceive: rcv_Data<=" + TxUtils.bytesToHexString(precbuff));
            return 1;
        }

        Log.d(TAG, "callbakHidTransceive: failed, len=" + len);
        return 0;

    }
}
